package aceim.app.view.page.accounteditor; import java.io.File; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.List; import aceim.api.dataentity.ProtocolOption; import aceim.api.dataentity.tkv.FileTKV; import aceim.api.dataentity.tkv.ListTKV; import aceim.api.dataentity.tkv.StringTKV; import aceim.api.dataentity.tkv.ToggleTKV; import aceim.api.service.ApiConstants; import aceim.api.utils.Logger; import aceim.api.utils.Logger.LoggerLevel; import aceim.app.AceImException; import aceim.app.MainActivity; import aceim.app.R; import aceim.app.dataentity.Account; import aceim.app.dataentity.ActivityResult; import aceim.app.dataentity.ProtocolResources; import aceim.app.dataentity.listeners.IHasFilePicker; import aceim.app.service.ServiceUtils; import aceim.app.utils.ViewUtils; import aceim.app.view.page.Page; import aceim.app.widgets.bottombar.BottomBarButton; import aceim.app.widgets.pickers.CalendarPickerListenerBase; import aceim.app.widgets.pickers.DatePickerListener; import aceim.app.widgets.pickers.FilePickerListener; import aceim.app.widgets.pickers.PickerListenerBase.ValuePickedListener; import aceim.app.widgets.pickers.TimePickerListener; import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.RemoteException; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.EditText; import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.LinearLayout.LayoutParams; import android.widget.Spinner; import android.widget.TextView; @SuppressLint("InlinedApi") public class AccountEditor extends Page implements IHasFilePicker { private static final LayoutParams LIST_PARAMS = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); private ArrayAdapter<ProtocolResources> mAdapter; private ProtocolResources mSelectedResources; private final Account mAccount; private List<ProtocolOption> mOptions; private boolean mHasUnsavedChanges = false; private final OnClickListener mCancelClickListener = new OnClickListener() { @Override public void onClick(View v) { final MainActivity activity = (MainActivity) getMainActivity(); if (mHasUnsavedChanges) { final AlertDialog dialog = new AlertDialog.Builder(activity) .setTitle(R.string.unsaved_data) .setPositiveButton(R.string.save, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { mSaveClickListener.onClick(null); dialog.dismiss(); } }) .setNegativeButton(R.string.dont_save, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); removeMe(); } }) .setNeutralButton(R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }) .create(); dialog.show(); } else { removeMe(); } } }; private final OnClickListener mSaveClickListener = new OnClickListener() { @Override public void onClick(View clicked) { MainActivity activity = (MainActivity) getMainActivity(); //if protocol still not chosen if (mOptions == null) { return; } final LinearLayout container = (LinearLayout) getView().findViewById(R.id.container); boolean areMandatoryFieldsFilled = true; ProtocolOption keyOption = mOptions.get(0); if (TextUtils.isEmpty(keyOption.getValue()) || keyOption.getValue().trim().length() < 1) { ViewUtils.showAlertToast(activity, android.R.drawable.ic_dialog_alert, R.string.unfilled_key_field, keyOption.getKey()); container.getChildAt(0).setBackgroundResource(R.drawable.criteria_bad); return; } if (keyOption.getValue().indexOf(ApiConstants.GENERAL_DIVIDER) > -1) { ViewUtils.showAlertToast(activity, android.R.drawable.ic_dialog_alert, R.string.key_field_contain_spaces, keyOption.getKey()); container.getChildAt(0).setBackgroundResource(R.drawable.criteria_bad); return; } for (int i = 1; i < mOptions.size(); i++) { ProtocolOption o = mOptions.get(i); View v = container.getChildAt(i); if (!checkValueMandatory(o, v)) { v.setBackgroundResource(R.drawable.criteria_bad); areMandatoryFieldsFilled = false; } else { v.setBackgroundResource(0); if (o.getValue() == null) { o.setValue(o.getDefaultValue()); } } } if (!areMandatoryFieldsFilled) { ViewUtils.showAlertToast(activity, android.R.drawable.ic_dialog_alert, R.string.unfilled_mandatory_warning, null); return; } try { if (mAccount == null) { Account account = activity.getCoreService().createAccount(mSelectedResources.getPackageId(), mOptions); if (account == null) { Logger.log("Cannot create account #" + mOptions.get(0).getValue(), LoggerLevel.INFO); return; } else { activity.accountAdded(account); } } else { activity.getCoreService().editAccount(mAccount, mOptions, mSelectedResources.getPackageId()); } } catch (RemoteException e) { activity.onRemoteException(e); } removeMe(); } }; private void saveValueToToption(String value, ProtocolOption option) { if (value.equals(option.getValue())) { return; } mHasUnsavedChanges = true; option.setValue(value); } private boolean checkValueMandatory(ProtocolOption o, View v) { return !o.isMandatory() || !TextUtils.isEmpty(o.getValue()); } public AccountEditor(Account account) { this.mAccount = account; } @Override public View createView(LayoutInflater inflater, ViewGroup group, Bundle saved) { MainActivity activity = (MainActivity) getMainActivity(); Collection<ProtocolResources> resources = obtainResourcesForEditor(); this.mAdapter = new ArrayAdapter<ProtocolResources>(activity.getApplicationContext(), android.R.layout.simple_spinner_item, resources.toArray(new ProtocolResources[resources.size()])); this.mAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); View view = inflater.inflate(R.layout.account_editor, group, false); final LinearLayout container = (LinearLayout) view.findViewById(R.id.container); Spinner protocolSpinner = (Spinner) view.findViewById(R.id.protocols); protocolSpinner.setAdapter(mAdapter); protocolSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { mSelectedResources = (ProtocolResources) parent.getItemAtPosition(position); constructEditor(container); } @Override public void onNothingSelected(AdapterView<?> parent) { container.removeAllViews(); } }); if (mAccount != null) { for (int i = 0; i < mAdapter.getCount(); i++) { if (mAdapter.getItem(i).getPackageId().equals(mAccount.getProtocolServicePackageName())) { protocolSpinner.setSelection(i); break; } } protocolSpinner.setEnabled(mAccount.getProtocolServicePackageName() == null); } BottomBarButton cancelBtn = (BottomBarButton) view.findViewById(R.id.cancel); BottomBarButton saveBtn = (BottomBarButton) view.findViewById(R.id.save); cancelBtn.setOnClickListener(mCancelClickListener); saveBtn.setOnClickListener(mSaveClickListener); return view; } private Collection<ProtocolResources> obtainResourcesForEditor() { List<ProtocolResources> res = new ArrayList<ProtocolResources>(); for (ProtocolResources r : getMainActivity().getProtocolResources().values()) { if (mAccount != null && !r.getProtocolName().equals(mAccount.getProtocolName())) { continue; } res.add(r); } if (res.size() > 0) { return res; } else { return getMainActivity().getProtocolResources().values(); } } private void constructEditor(LinearLayout container) { container.removeAllViews(); MainActivity activity = (MainActivity) getMainActivity(); Resources resources; try { resources = mSelectedResources.getNativeResourcesForProtocol(getMainActivity().getPackageManager()); mOptions = activity.getCoreService().getProtocolOptions(mSelectedResources.getPackageId(), mAccount!=null ? mAccount.getServiceId() : (byte)-1); } catch (RemoteException e) { activity.onRemoteException(e); return; } catch (AceImException e) { Logger.log(e); return; } LayoutInflater inflater = LayoutInflater.from(activity); if (mAccount != null) { if (mOptions.size() > 0 && TextUtils.isEmpty(mOptions.get(0).getValue())) { mOptions.get(0).setValue(mAccount.getProtocolUid()); } } for (ProtocolOption o : mOptions) { View item; if (o.getTkv() instanceof FileTKV) { item = fillDialogItem(inflater, o, new FilePickerListener(o.getTkv(), new ProtocolOptionValuePickedListener(o), getMainActivity())); } else if (o.getTkv() instanceof ListTKV) { item = inflater.inflate(R.layout.options_item_list, null); Spinner spinner = (Spinner) item.findViewById(R.id.value); ListTKV list = (ListTKV) o.getTkv(); ArrayAdapter<String> adapter = new ArrayAdapter<String>(getMainActivity(), android.R.layout.simple_spinner_item, android.R.id.text1, list.getChoices()); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinner.setAdapter(adapter); for (int i=0; i<list.getChoices().length; i++) { if (list.getChoices()[i].equals(list.getValue())) { spinner.setSelection(i); break; } } spinner.setEnabled(mAccount == null || mOptions.get(0) != o); } else if (o.getTkv() instanceof ToggleTKV) { item = inflater.inflate(R.layout.options_item_checkbox, null); CheckBox cb = (CheckBox) item.findViewById(R.id.value); boolean b; if (o.getValue() != null) { b = Boolean.parseBoolean(o.getValue()); } else { b = Boolean.parseBoolean(o.getDefaultValue()); o.setValue(o.getDefaultValue()); } cb.setChecked(b); cb.setOnCheckedChangeListener(new ToggleTKVChangedListener(o)); cb.setEnabled(mOptions.get(0) != o); } else if (o.getTkv() instanceof StringTKV) { StringTKV tkv = (StringTKV) o.getTkv(); switch (tkv.getContentType()) { case DATE: item = fillDialogItem(inflater, o, new DatePickerListener(o.getTkv(), new ProtocolOptionValuePickedListener(o), getMainActivity())); break; case TIME: item = fillDialogItem(inflater, o, new TimePickerListener(o.getTkv(), new ProtocolOptionValuePickedListener(o), getMainActivity())); break; /*case CHECKBOX: item = inflater.inflate(R.layout.options_item_checkbox, null); CheckBox cb = (CheckBox) item.findViewById(R.id.value); boolean b; if (o.getValue() != null) { b = Boolean.parseBoolean(o.getValue()); } else { b = Boolean.parseBoolean(o.getDefaultValue()); o.setValue(o.getDefaultValue()); } cb.setChecked(b); break;*/ case DOUBLE: item = fillEditTextItem(R.layout.options_item_double, inflater, o); break; case INTEGER: item = fillEditTextItem(R.layout.options_item_integer, inflater, o); break; case PASSWORD: item = fillEditTextItem(R.layout.options_item_password, inflater, o); break; case STRING: item = fillEditTextItem(R.layout.options_item_text, inflater, o); break; default: item = fillDialogItem(inflater, o, null); break; } } else { item = fillDialogItem(inflater, o, null); } ((TextView) item.findViewById(R.id.label)).setText(resources.getString(o.getLabelId())); item.setTag(o.getKey()); container.addView(item, LIST_PARAMS); } } private View fillDialogItem(LayoutInflater inflater, ProtocolOption o, OnClickListener clickListener) { View item = inflater.inflate(R.layout.options_item, null); ImageButton editBtn = (ImageButton) item.findViewById(R.id.edit); editBtn.setImageResource(android.R.drawable.ic_menu_edit); if (clickListener != null && (mAccount == null || mOptions.get(0) != o)) { editBtn.setOnClickListener(clickListener); } else { editBtn.setVisibility(View.INVISIBLE); } TextView tvalue = (TextView) item.findViewById(R.id.value); if (o.getValue() != null) { if (o.getTkv() instanceof FileTKV) { setFileItemLabelValue(item, o.getValue()); } else if (o.getTkv() instanceof StringTKV) { StringTKV tkv = (StringTKV) o.getTkv(); switch (tkv.getContentType()) { case DATE: case TIME: CalendarPickerListenerBase l = (CalendarPickerListenerBase) clickListener; long timeMillis = Long.parseLong(o.getValue()); Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(timeMillis); tvalue.setText(l.getFormat().format(cal.getTime())); break; default: tvalue.setText(o.getValue()); break; } } else if (o.getTkv() instanceof ListTKV) { //TODO } } return item; } private View fillEditTextItem(int layoutId, LayoutInflater inflater, final ProtocolOption o) { View item = inflater.inflate(layoutId, null); final EditText et = ((EditText) item.findViewById(R.id.value)); String value; if (o.getValue() != null) { value = o.getValue(); } else if (o.getDefaultValue() != null) { value = o.getDefaultValue(); o.setValue(o.getDefaultValue()); } else { value = null; } et.setText(value); et.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) {} @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void afterTextChanged(Editable s) { o.setValue(et.getText().toString()); mHasUnsavedChanges = true; } }); et.setEnabled(mAccount == null || mOptions.get(0) != o); return item; } private static void setFileItemLabelValue(View item, String value) { TextView tvalue = (TextView) item.findViewById(R.id.value); if (value != null) { tvalue.setText(new File(value).getName()); } else { tvalue.setText(null); } } @Override public Drawable getIcon(Context context) { return context.getResources().getDrawable(android.R.drawable.ic_menu_manage); } @Override public String getTitle(Context context) { if (mAccount != null) { return mAccount.getSafeName(); } else { return context.getResources().getString(R.string.new_account); } } @Override public String getPageId(){ return getClass().getSimpleName() + (mAccount != null ? (" " + mAccount.getAccountId()) : ""); } @Override public void onFilePicked(ActivityResult result, MainActivity activity) { switch (result.getResultCode()) { case Activity.RESULT_OK: for (int i = 0; i < mOptions.size(); i++) { ProtocolOption o = mOptions.get(i); if (ServiceUtils.getRequestCodeForActivity(o.getKey().hashCode()) == result.getRequestCode()) { LinearLayout container = (LinearLayout) getView().findViewById(R.id.container); View item = container.getChildAt(i); String filePath = result.getData().getData().getPath(); saveValueToToption(filePath, o); setFileItemLabelValue(item, filePath); break; } } break; } } private final class ProtocolOptionValuePickedListener implements ValuePickedListener { private final ProtocolOption option; private ProtocolOptionValuePickedListener(ProtocolOption option) { this.option = option; } @Override public void onValuePicked(String value) { saveValueToToption(value, option); } } private final class ToggleTKVChangedListener implements OnCheckedChangeListener { private final ProtocolOption o; private ToggleTKVChangedListener(ProtocolOption o) { this.o = o; } @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { o.setValue(Boolean.toString(isChecked)); } } }